#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#include <iostream>
#include <time.h>
#include <fstream>
#include "init_opencl.hpp"

using namespace std;

OpenCLEnv::OpenCLEnv() {
	clock_t init, final;
	init=clock();
	try {
		// Get available platforms
		vector<cl::Platform> platforms;
		cl::Platform::get(&platforms);

		string platformVendor;
		cout << "Nr of platforms: " << platforms.size() << endl;
		for(int i = 0; i < platforms.size() ; i++) {
			platforms[i].getInfo((cl_platform_info)CL_PLATFORM_VENDOR, &platformVendor);
			cout << "Platform "<< i << " is by: " << platformVendor << endl;
		}

		// Select the default platform and create a context using this platform
		cl_context_properties cps[3] = {
			CL_CONTEXT_PLATFORM,
			(cl_context_properties)(platforms[0])(),
			0
		};

		context = cl::Context(CL_DEVICE_TYPE_ALL, cps);

		// Get a list of devices on this platform
		devices = context.getInfo<CL_CONTEXT_DEVICES>();


		//http://svn.clifford.at/tools/trunk/examples/cldemo.c

		cl_platform_id platformsId[100];
		cl_uint platforms_n = 0;
		clGetPlatformIDs(100, platformsId, &platforms_n);

		cl_device_id devicesId[100];
		cl_uint devices_n = 0;

		clGetDeviceIDs(platformsId[0], CL_DEVICE_TYPE_ALL, 100, devicesId, &devices_n);

		cout << "Nr of devices: " << devices.size() << endl;
		cout << "Devices: " << endl;
		for(int i = 0; i < devices_n; i++) {
			char buffer[10240];
			cl_uint buf_uint;
			cl_ulong buf_ulong;

			clGetDeviceInfo(devicesId[i], CL_DEVICE_NAME, sizeof(buffer), buffer, NULL);
			cout << "  DEVICE_NAME = " << buffer << endl;
			clGetDeviceInfo(devicesId[i], CL_DEVICE_VENDOR, sizeof(buffer), buffer, NULL);
			cout << "  DEVICE_VENDOR = " << buffer << endl;
			clGetDeviceInfo(devicesId[i], CL_DEVICE_VERSION, sizeof(buffer), buffer, NULL);
			cout << "  DEVICE_VERSION = " << buffer << endl;
			clGetDeviceInfo(devicesId[i], CL_DRIVER_VERSION, sizeof(buffer), buffer, NULL);
			cout << "  DRIVER_VERSION = " << buffer << endl;
			clGetDeviceInfo(devicesId[i], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(buf_uint), &buf_uint, NULL);
			cout << "  DEVICE_MAX_COMPUTE_UNITS = " << (unsigned int)buf_uint << endl;
			clGetDeviceInfo(devicesId[i], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(buf_uint), &buf_uint, NULL);
			cout << "  DEVICE_MAX_CLOCK_FREQUENCY = " << (unsigned int)buf_uint << endl;
			clGetDeviceInfo(devicesId[i], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(buf_ulong), &buf_ulong, NULL);
			cout << "  DEVICE_GLOBAL_MEM_SIZE = " << (unsigned long long)buf_ulong << endl;
			cout << endl;
		}

		// Create a command queue and choose a device (0=CPU, 1=GPU, need to make a check here)		
		queue1 = cl::CommandQueue(context, devices[1]);
		queue2 = cl::CommandQueue(context, devices[0]);

	} catch(cl::Error error) {
		cout << error.what() << "(" << error.err() << ")" << endl;
	}

	final=clock()-init;
	cout << "OpenCL initialization took: " << (double)final / ((double)CLOCKS_PER_SEC) << " seconds." << endl;
}
